/*
 * Copyright 2011 Ytai Ben-Tsvi. All rights reserved.
 *  
 * 
 * Redistribution and use in source and binary forms, with or without modification, are
 * permitted provided that the following conditions are met:
 * 
 *    1. Redistributions of source code must retain the above copyright notice, this list of
 *       conditions and the following disclaimer.
 * 
 *    2. Redistributions in binary form must reproduce the above copyright notice, this list
 *       of conditions and the following disclaimer in the documentation and/or other materials
 *       provided with the distribution.
 * 
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ARSHAN POURSOHI OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * The views and conclusions contained in the software and documentation are those of the
 * authors and should not be interpreted as representing official policies, either expressed
 * or implied.
 */
package ioio.lib.api;

import ioio.lib.api.exception.ConnectionLostException;

/**
 * An interface for pulse width and frequency measurements of digital signals.
 * <p>
 * PulseInput (commonly known as "input capture") is a versatile module which
 * enables extraction of various timing information from a digital signal. There
 * are two main use cases: pulse duration measurement and frequency measurement.
 * In pulse width measurement we measure the duration of a positive ("high") or
 * negative ("low") pulse, i.e. the elapsed time between a rise and a fall or
 * vice versa. This mode is useful, for example, for decoding a PWM signal or
 * measuring the delay of a sonar return signal. In frequency measurement we
 * measure the duration between a rising edge to the following rising edge. This
 * gives us a momentary reading of a signal's frequency or period. This is
 * commonly used, for example, in conjunction with an optical or magnetic sensor
 * for measuring a turning shaft's speed.
 * <p>
 * {@link PulseInput} instances are obtained by calling
 * {@link IOIO#openPulseInput(ioio.lib.api.DigitalInput.Spec, ClockRate, PulseMode, boolean)}
 * . When created, some important configuration decisions have to be made: the
 * precision (single or double), the clock rate and the mode of operation. Modes
 * are straightforward: {@link PulseMode.POSITIVE} is used for measuring a
 * positive pulse, {@link PulseMode.NEGATIVE} a negative pulse, and
 * {@link PulseMode.FREQ} / {@link PulseMode.FREQ_SCALE_4} /
 * {@link PulseMode.FREQ_SCALE_16} are used for measuring frequency. The
 * difference between the three scaling modes is that without scaling, the
 * frequency is determined by measurement of a single
 * (rising-edge-to-rising-edge) period. In x4 scaling, 4 consecutive periods are
 * measured and the time is divided by 4, providing some smoothing as well as
 * better resolution. Similarly for x16 scaling. Note that scaling affects the
 * range of signals to be measured, as discussed below.
 * <p>
 * The choice of single vs. double-precision is important to understand: IOIO
 * internally uses either 16-bit counters or 32-bit counters for the timing. 16-
 * counters force us to either limit the maximum duration (and the minimum
 * frequency) or compromise accuracy as compared to 32-bit counters. However, if
 * you need many concurrent pulse measurements in your application, you may have
 * no choice but to use single-precision.
 * <p>
 * The clock rate selection is important (and even critical when working in
 * single-precision) and requires the user to make some assumptions about the
 * nature of the measured signal. The higher the clock rate, the more precise
 * the measurement, but the longest pulse that can be measured decreases (or
 * lowest frequency that can be measured increases). Using the scaling option
 * when operating in frequency mode also affects these sizes. combinations. It
 * is always recommended to choose the most precise mode, which exceeds the
 * maximum expected pulse width (or inverse frequency). If a pulse is received
 * whom duration exceeds the longest allowed pulse, it will be "folded" into the
 * valid range and product garbage readings.
 * <p>
 * The following table (sorted by longest pulse) summarizes all possible clock /
 * mode combinations. The table applies for <b>single-precision</b> operation.
 * For double-precision, simply multiply the longest pulse by 65536 and divide
 * the lowest frequency by the same amount. Interestingly, the number written in
 * [ms] units in the longest pulse column, roughly corresponds to the same
 * number in minutes when working with double precsion, since 1[min] =
 * 60000[ms].
 * <table border="1">
 * <tr>
 * <th>Clock</th>
 * <th>Scaling</th>
 * <th>Resolution</th>
 * <th>Longest pulse</th>
 * <th>Lowest frequency</th>
 * </tr>
 * <tr>
 * <td>62.5KHz</td>
 * <td>1</td>
 * <td>16us</td>
 * <td>1.048s</td>
 * <td>0.95Hz</td>
 * </tr>
 * <tr>
 * <td>250KHz</td>
 * <td>1</td>
 * <td>4us</td>
 * <td>262.1ms</td>
 * <td>3.81Hz</td>
 * </tr>
 * <tr>
 * <td>62.5KHz</td>
 * <td>4</td>
 * <td>4us</td>
 * <td>262.1ms</td>
 * <td>3.81Hz</td>
 * </tr>
 * <tr>
 * <td>250KHz</td>
 * <td>4</td>
 * <td>1us</td>
 * <td>65.54ms</td>
 * <td>15.26Hz</td>
 * </tr>
 * <tr>
 * <td>62.5KHz</td>
 * <td>16</td>
 * <td>1us</td>
 * <td>65.54ms</td>
 * <td>15.26Hz</td>
 * </tr>
 * <tr>
 * <td>2MHz</td>
 * <td>1</td>
 * <td>500ns</td>
 * <td>32.77ms</td>
 * <td>30.52Hz</td>
 * </tr>
 * <tr>
 * <td>250KHz</td>
 * <td>16</td>
 * <td>250us</td>
 * <td>16.38ms</td>
 * <td>61.0Hz</td>
 * </tr>
 * <tr>
 * <td>2MHz</td>
 * <td>4</td>
 * <td>125ns</td>
 * <td>8.192ms</td>
 * <td>122.1Hz</td>
 * </tr>
 * <tr>
 * <td>16MHz</td>
 * <td>1</td>
 * <td>62.5ns</td>
 * <td>4.096ms</td>
 * <td>244.1Hz</td>
 * </tr>
 * <tr>
 * <td>2MHz</td>
 * <td>16</td>
 * <td>31.25ns</td>
 * <td>2.048ms</td>
 * <td>488.3Hz</td>
 * </tr>
 * <tr>
 * <td>16MHz</td>
 * <td>4</td>
 * <td>15.6ns</td>
 * <td>1.024ms</td>
 * <td>976.6Hz</td>
 * </tr>
 * <tr>
 * <td>16MHz</td>
 * <td>16</td>
 * <td>3.9ns</td>
 * <td>256us</td>
 * <td>3.906KHz</td>
 * </tr>
 * </table>
 * 
 * <p>
 * In some applications it is desirable to measure every incoming pulse rather
 * than repetitively query the result of the last measurement. For that purpose
 * the {@link #waitPulseGetDuration()} method exists: every incoming pulse width
 * is pushed into a small internal queue from which it can be read. The client
 * waits for data to be available, then reads it and data that comes in in the
 * meanwhile is stored. The queue has limited size, so it is important to read
 * quickly if no pulses are to be lost. Note that once a pulse is detected, the
 * next one must have its leading edge at least 5ms after the leading edge of
 * the current one, or else it will be skipped. This throttling has been
 * introduced on purpose, in order to prevent saturation the communication
 * channel when the input signal is very high frequency. Effectively, this means
 * that the maximum sample rate is 200Hz. This rate has been chosen as it
 * enables measure R/C servo signals without missing pulses.
 * 
 * <p>
 * Typical usage (servo signal pulse width measurement):
 * 
 * <pre>
 * {@code
 * // Open pulse input at 16MHz, double-precision
 * PulseInput in = ioio.openPulseInput(3, PulseMode.POSITIVE);
 * ...
 * float widthSec = in.getDuration();
 * OR:
 * float widthSec = in.waitPulseGetDuration();
 * ... 
 * in.close();  // pin 3 can now be used for something else.
 * }
 * </pre>
 * 
 * <p>
 * Typical usage (frequency measurement):
 * 
 * <pre>
 * {@code
 * // Signal is known to be slightly over 150Hz. Single precision can be used.
 * PulseInput in = ioio.openPulseInput(3,
 *                                     ClockRate.RATE_2MHz,
 *                                     PulseMode.FREQ_SCALE_4,
 *                                     false);
 * ...
 * float freqHz = in.getFrequency();
 * ... 
 * in.close();  // pin 3 can now be used for something else.
 * }
 * </pre>
 */
public interface PulseInput extends Closeable {
	/** An enumeration for describing the module's operating mode. */
	public enum PulseMode {
		/** Positive pulse measurement (rising-edge-to-falling-edge). */
		POSITIVE(1),
		/** Negative pulse measurement (falling-edge-to-rising-edge). */
		NEGATIVE(1),
		/** Frequency measurement (rising-edge-to-rising-edge). */
		FREQ(1),
		/** Frequency measurement (rising-edge-to-rising-edge) with 4x scaling. */
		FREQ_SCALE_4(4),
		/** Frequency measurement (rising-edge-to-rising-edge) with 16x scaling. */
		FREQ_SCALE_16(16);

		/** The scaling factor as an integer. */
		public final int scaling;

		private PulseMode(int s) {
			scaling = s;
		}
	}

	/** Suported clock rate enum. */
	public enum ClockRate {
		/** 16MHz */
		RATE_16MHz(16000000),
		/** 2MHz */
		RATE_2MHz(2000000),
		/** 250KHz */
		RATE_250KHz(250000),
		/** 62.5KHz */
		RATE_62KHz(62500);

		/** The value in Hertz units. */
		public final int hertz;

		private ClockRate(int h) {
			hertz = h;
		}
	}

	/**
	 * Gets the pulse duration in case of pulse measurement mode, or the period
	 * in case of frequency mode. When scaling is used, this is compensated for
	 * here, so the duration of a single cycle will be returned.
	 * <p>
	 * The first call to this method may block shortly until the first data
	 * update arrives. The client may interrupt the calling thread.
	 * 
	 * @return The duration, in seconds.
	 * @throws InterruptedException
	 *             The calling thread has been interrupted.
	 * @throws ConnectionLostException
	 *             The connection with the IOIO has been lost.
	 */
	public float getDuration() throws InterruptedException,
			ConnectionLostException;

	/**
	 * Reads a single measurement from the queue. If the queue is empty, will
	 * block until more data arrives. The calling thread may be interrupted in
	 * order to abort the call. See interface documentation for further
	 * explanation regarding the read queue.
	 * <p>
	 * This method may not be used if the interface has was opened in frequency
	 * mode.
	 * 
	 * @return The duration, in seconds.
	 * @throws InterruptedException
	 *             The calling thread has been interrupted.
	 * @throws ConnectionLostException
	 *             The connection with the IOIO has been lost.
	 */
	public float waitPulseGetDuration() throws InterruptedException,
			ConnectionLostException;

	/**
	 * Gets the momentary frequency of the measured signal. When scaling is
	 * used, this is compensated for here, so the true frequency of the signal
	 * will be returned.
	 * <p>
	 * The first call to this method may block shortly until the first data
	 * update arrives. The client may interrupt the calling thread.
	 * 
	 * @return The frequency, in Hz.
	 * @throws InterruptedException
	 *             The calling thread has been interrupted.
	 * @throws ConnectionLostException
	 *             The connection with the IOIO has been lost.
	 */
	public float getFrequency() throws InterruptedException,
			ConnectionLostException;
}
